package com.easychat.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import com.easychat.config.AppConfig;
import com.easychat.entity.constants.Constants;
import com.easychat.entity.dto.MessageSendDTO;
import com.easychat.entity.dto.SysSettingDto;
import com.easychat.entity.dto.TokenUserInfoDto;
import com.easychat.entity.enums.*;
import com.easychat.entity.po.*;
import com.easychat.entity.query.*;
import com.easychat.exception.BusinessException;
import com.easychat.mappers.*;
import com.easychat.service.UserContactApplyService;
import com.easychat.utils.CopyTools;
import com.easychat.utils.RedisUtil;
import com.easychat.websocket.ChannelContextUtils;
import com.easychat.websocket.MessageHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.easychat.entity.vo.PaginationResultVO;
import com.easychat.service.GroupInfoService;
import com.easychat.utils.StringTools;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;


/**
 *  业务接口实现
 */
@Service("groupInfoService")
public class GroupInfoServiceImpl implements GroupInfoService {

	@Resource
	private GroupInfoMapper<GroupInfo, GroupInfoQuery> groupInfoMapper;

	@Resource
	private RedisUtil redisUtil;

	@Resource
	private UserContactMapper<UserContact, UserContactQuery> userContactMapper;

	@Resource
	private UserContactApplyService userContactApplyService;
	@Resource
	private AppConfig appConfig;

	@Resource
	@Lazy
	private GroupInfoService groupInfoService;

	@Resource
	private ChatSessionUserMapper<ChatSessionUser, ChatSessionUserQuery> chatSessionUserMapper;

	@Resource
	private ChatSessionMapper<ChatSession, ChatSessionQuery> chatSessionMapper;

	@Resource
	private UserInfoMapper<UserInfo, UserInfoQuery> userInfoMapper;

	@Resource
	private ChatMessageMapper<ChatMessage, ChatMessageQuery> chatMessageMapper;

	@Resource
	private ChannelContextUtils channelContextUtils;
    @Autowired
    private MessageHandler messageHandler;
    @Qualifier("redisTemplate")
    @Autowired
    private RedisTemplate redisTemplate;

	/**
	 * 根据条件查询列表
	 */
	@Override
	public List<GroupInfo> findListByParam(GroupInfoQuery param) {
		return this.groupInfoMapper.selectList(param);
	}

	/**
	 * 根据条件查询列表
	 */
	@Override
	public Integer findCountByParam(GroupInfoQuery param) {
		return this.groupInfoMapper.selectCount(param);
	}

	/**
	 * 分页查询方法
	 */
	@Override
	public PaginationResultVO<GroupInfo> findListByPage(GroupInfoQuery param) {
		int count = this.findCountByParam(param);
		int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

		SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
		param.setSimplePage(page);
		List<GroupInfo> list = this.findListByParam(param);
		PaginationResultVO<GroupInfo> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
		return result;
	}

	/**
	 * 新增
	 */
	@Override
	public Integer add(GroupInfo bean) {
		return this.groupInfoMapper.insert(bean);
	}

	/**
	 * 批量新增
	 */
	@Override
	public Integer addBatch(List<GroupInfo> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.groupInfoMapper.insertBatch(listBean);
	}

	/**
	 * 批量新增或者修改
	 */
	@Override
	public Integer addOrUpdateBatch(List<GroupInfo> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.groupInfoMapper.insertOrUpdateBatch(listBean);
	}

	/**
	 * 多条件更新
	 */
	@Override
	public Integer updateByParam(GroupInfo bean, GroupInfoQuery param) {
		StringTools.checkParam(param);
		return this.groupInfoMapper.updateByParam(bean, param);
	}

	/**
	 * 多条件删除
	 */
	@Override
	public Integer deleteByParam(GroupInfoQuery param) {
		StringTools.checkParam(param);
		return this.groupInfoMapper.deleteByParam(param);
	}

	/**
	 * 根据GroupId获取对象
	 */
	@Override
	public GroupInfo getGroupInfoByGroupId(String groupId) {
		return this.groupInfoMapper.selectByGroupId(groupId);
	}

	/**
	 * 根据GroupId修改
	 */
	@Override
	public Integer updateGroupInfoByGroupId(GroupInfo bean, String groupId) {
		return this.groupInfoMapper.updateByGroupId(bean, groupId);
	}

	/**
	 * 根据GroupId删除
	 */
	@Override
	public Integer deleteGroupInfoByGroupId(String groupId) {
		return this.groupInfoMapper.deleteByGroupId(groupId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveGroup(GroupInfo groupInfo, MultipartFile avatarFile, MultipartFile avatarCover) throws IOException {
		Date date = new Date();
		// 新增
		if (null == groupInfo.getGroupId()) {
			// 先查出创建了多少个群，因为有限制
			String groupOwnerId = groupInfo.getGroupOwnerId();
			GroupInfoQuery groupInfoQuery = new GroupInfoQuery();
			groupInfoQuery.setGroupOwnerId(groupOwnerId);
			Integer count = groupInfoMapper.selectCount(groupInfoQuery);
			SysSettingDto sysSetting = redisUtil.getSysSetting();
			if (count >= sysSetting.getMaxGroupCount()) {
				throw new BusinessException("创建群组数量已达到上限，最多只能创建" + sysSetting.getMaxGroupCount() + "个群组");
			}
			if (avatarFile == null) {
				throw new BusinessException(ResponseCodeEnum.CODE_600);
			}
			groupInfo.setCreateTime(date);
			// 新增的话，需要重新生成groupId
			groupInfo.setGroupId(StringTools.getGroupId());
			groupInfo.setStatus(1);
			groupInfoMapper.insert(groupInfo);

			// 将群组添加为联系人
			UserContact userContact = new UserContact();
			userContact.setStatus(UserContactStatusEnum.FRIEND.getStatus());
			userContact.setContactType(UserContactTypeEnum.GROUP.getType());
			userContact.setContactId(groupInfo.getGroupId());
			userContact.setUserId(groupOwnerId);
			userContact.setCreateTime(date);
			userContactMapper.insert(userContact);

			String sessionId = StringTools.getChatSessionId4Group(groupInfo.getGroupId());
			ChatSession chatSession = ChatSession.builder()
					.sessionId(sessionId)
					.lastMessage(MessageTypeEnum.GROUP_CREATE.getInitMessage())
					.lastReceiveTime(date.getTime())
					.build();
			this.chatSessionMapper.insert(chatSession);

			ChatSessionUser chatSessionUser = ChatSessionUser.builder()
					.userId(groupOwnerId)
					.contactId(groupInfo.getGroupId())
					.contactName(groupInfo.getGroupName())
					.sessionId(sessionId)
					.build();

			this.chatSessionUserMapper.insert(chatSessionUser);

			ChatMessage chatMessage = ChatMessage.builder()
					.sessionId(sessionId)
					.messageType(MessageTypeEnum.GROUP_CREATE.getType())
					.messageContent(MessageTypeEnum.GROUP_CREATE.getInitMessage())
					.sendTime(date.getTime())
					.contactId(groupInfo.getGroupId())
					.contactType(UserContactTypeEnum.GROUP.getType())
					.status(MessageStatusEnum.SENDED.getStatus())
					.build();

			this.chatMessageMapper.insert(chatMessage);

			// 将群组添加到联系人
			redisUtil.addUserContact(groupInfo.getGroupOwnerId(), groupInfo.getGroupId());

			// 将联系人添加到群组通道
			channelContextUtils.addUser2Group(groupOwnerId, groupInfo.getGroupId());

			// 发送ws消息
			chatSessionUser.setLastMessage(MessageTypeEnum.GROUP_CREATE.getInitMessage());
			chatSessionUser.setLastReceiveTime(date.getTime());
			// 获取人数
			chatSessionUser.setMemberCount(1);
			MessageSendDTO messageSendDTO = CopyTools.copy(chatSessionUser, MessageSendDTO.class);
			messageSendDTO.setExtendData(chatSessionUser);
			messageSendDTO.setLastMessage(chatSession.getLastMessage());
			messageHandler.sendMessage(messageSendDTO);

		} else {
			// 修改
			GroupInfo dbGroupInfo = groupInfoMapper.selectByGroupId(groupInfo.getGroupId());
			if (!dbGroupInfo.getGroupOwnerId().equals(groupInfo.getGroupOwnerId())) {
				throw new BusinessException(ResponseCodeEnum.CODE_600);
			}
			groupInfoMapper.updateByGroupId(groupInfo, groupInfo.getGroupId());
			// 更新相关表冗余信息
			String contactUpdateName = null;
			if (!dbGroupInfo.getGroupName().equals(groupInfo.getGroupName())) {
				contactUpdateName = groupInfo.getGroupName();
			}
			if (null == contactUpdateName) {
				return;
			}
			this.chatSessionUserMapper.updateContactName(groupInfo.getGroupId(), contactUpdateName);

			MessageSendDTO messageSendDTO = new MessageSendDTO();
			messageSendDTO.setContactType(UserContactTypeEnum.GROUP.getType());
			messageSendDTO.setContactId(groupInfo.getGroupId());
			messageSendDTO.setExtendData(contactUpdateName);
			messageSendDTO.setMessageType(MessageTypeEnum.CONTACT_NAME_UPDATE.getType());
			messageHandler.sendMessage(messageSendDTO);

		}
		// 上传群头像
		if (null == avatarFile) {
			return;
		}
		String baseFolder = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE;
		File targetFileFolder = new File(baseFolder + Constants.FILE_FOLDER_AVATAR_NAME);
		if (!targetFileFolder.exists()) {
			targetFileFolder.mkdir();
		}
		String filePath = targetFileFolder.getPath() + "/" + groupInfo.getGroupOwnerId() + Constants.IMAGE_SUFFIX;

		avatarFile.transferTo(new File(filePath));
		if (avatarCover != null) {
			avatarCover.transferTo(new File(filePath + Constants.COVER_IMAGE_SUFFIX));
		}

	}

	@Override
	public List<GroupInfo> selectMyGroupList(String userId) {
		return groupInfoMapper.selectMyGroupList(userId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void dissolutionGroup(String groupOwnerId, String groupId) {
		GroupInfo dbGroupInfo = groupInfoMapper.selectByGroupId(groupId);

		if (null == dbGroupInfo || !dbGroupInfo.getGroupOwnerId().equals(groupOwnerId)) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		GroupInfo groupInfo = new GroupInfo();
		groupInfo.setStatus(GroupStatusEnum.DISBAND.getStatus());
		this.groupInfoMapper.updateByGroupId(groupInfo, groupId);

		// 更新联系人信息
		userContactMapper.updateContactStatus(groupId, UserContactTypeEnum.GROUP.getType());

		// 查出所有的群员
		UserContactQuery userContactQuery = new UserContactQuery();
		userContactQuery.setContactId(groupId);
		userContactQuery.setContactType(UserContactTypeEnum.GROUP.getType());
		userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getStatus());

		List<UserContact> userContactList = this.userContactMapper.selectList(userContactQuery);
		for (UserContact userContact : userContactList) {
			redisTemplate.opsForList().remove(Constants.REDIS_KEY_USER_CONTACT + userContact.getUserId(), 0, userContact.getContactId());
		}

		String sessionId = StringTools.getChatSessionId4Group(groupId);
		Date curDate = new Date();
		String messageContent = MessageTypeEnum.DISSOLUTION_GROUP.getInitMessage();
		ChatSession chatSession = ChatSession.builder()
				.lastMessage(messageContent)
				.lastReceiveTime(curDate.getTime())
				.sessionId(sessionId)
				.build();

		this.chatSessionMapper.updateBySessionId(chatSession, sessionId);

		ChatMessage chatMessage = ChatMessage.builder()
				.sessionId(sessionId)
				.sendTime(curDate.getTime())
				.contactType(UserContactTypeEnum.GROUP.getType())
				.status(MessageStatusEnum.SENDED.getStatus())
				.messageType(MessageTypeEnum.DISSOLUTION_GROUP.getType())
				.contactId(groupId)
				.messageContent(messageContent)
				.build();

		this.chatMessageMapper.insert(chatMessage);

		MessageSendDTO messageSendDTO = CopyTools.copy(chatMessage, MessageSendDTO.class);
		messageHandler.sendMessage(messageSendDTO);
	}

	@Override
	public void addOrRemoveGroupUser(TokenUserInfoDto tokenUserInfoDto, String groupId, String selectContacts, Integer opType) {
		GroupInfo groupInfo = this.groupInfoMapper.selectByGroupId(groupId);
		if (null == groupInfo || !groupInfo.getGroupOwnerId().equals(tokenUserInfoDto.getUserId())) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}

		String[] contactIdList = selectContacts.split(",");
		for (String contactId : contactIdList) {
			if (opType.equals(0)) {
				// 移除
//				this.leaveGroup()
				// 不能内部调用，这个方法没有加上事务，调用的有事务，事务是失效的
				groupInfoService.leaveGroup(contactId, groupId, MessageTypeEnum.REMOVE_GROUP);
			} else {
				userContactApplyService.addContact(contactId, null, groupId, UserContactTypeEnum.GROUP.getType(), null);
			}
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void leaveGroup(String userId, String groupId, MessageTypeEnum messageTypeEnum) {
		GroupInfo groupInfo = this.groupInfoMapper.selectByGroupId(groupId);
		if (null == groupInfo) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		if (userId.equals(groupInfo.getGroupOwnerId())) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		Integer count = this.userContactMapper.deleteByUserIdAndContactId(userId, groupId);
		if (count == 0) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}

		UserInfo userInfo = this.userInfoMapper.selectByUserId(userId);
		String sessionId = StringTools.getChatSessionId4Group(groupId);
		Date curDate = new Date();
		String messageContent = String.format(messageTypeEnum.getInitMessage(), userInfo.getNickName());

		ChatSession chatSession = ChatSession.builder()
				.lastReceiveTime(curDate.getTime())
				.lastMessage(messageContent)
				.build();

		this.chatSessionMapper.updateBySessionId(chatSession, sessionId);

		ChatMessage chatMessage = ChatMessage.builder()
				.sessionId(sessionId)
				.sendTime(curDate.getTime())
				.contactType(UserContactTypeEnum.GROUP.getType())
				.status(MessageStatusEnum.SENDED.getStatus())
				.messageType(messageTypeEnum.getType())
				.contactId(groupId)
				.messageContent(messageContent)
				.build();

		this.chatMessageMapper.insert(chatMessage);

		UserContactQuery userContactQuery = new UserContactQuery();
		userContactQuery.setContactId(groupId);
		userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getStatus());

		Integer memberCount = this.userContactMapper.selectCount(userContactQuery);

		MessageSendDTO messageSendDTO = CopyTools.copy(chatMessage, MessageSendDTO.class);
		messageSendDTO.setExtendData(userId);
		messageSendDTO.setMemberCount(memberCount);
		messageHandler.sendMessage(messageSendDTO);

	}
}